/* ========================================
 *
 * Copyright Nano IC, 2021-02-25
 * All Rights Reserved
 * UNPUBLISHED, LICENSED SOFTWARE.
 *
 * CONFIDENTIAL AND PROPRIETARY INFORMATION
 * WHICH IS THE PROPERTY OF Nano IC.
 *
 * ========================================
*/
#include <csi_core.h>
#include "one_wire_bus_queue.h"
#include "one_wire_bus_app.h"

/**
 * @brief :块状队列的初始化
 * 
 * @param q: 块状队列控制数据结构
 * @param p_buf :块状队列数据保缓冲指针
 * @param one_bolck_len : 每一个块状队列的长度，块状队列每块固定长度，头两个字节表示总长度
 * @param total_block_num : 块状队列的总数量
 * @return true :成功
 * @return false :失败
 */
bool block_queue_create(BlockQueueStruct *q , uint8_t *p_buf ,uint16_t one_bolck_len , uint16_t total_block_num)
{
    if(one_bolck_len > ONE_BLOCK_QUEUE_MAX_LENGTH)
    {
        return false;
    }
    if(one_bolck_len < 4)
    {
        return false;
    }
    if(total_block_num > BLOCK_QUEUE_MAX_SIZE)
    {
        return false;
    }
    for(uint16_t i=0;i<total_block_num;i++)
    {
        q->qu[i] = p_buf;
        p_buf += one_bolck_len;
    }
    
    q->head = 0;
    q->tail = 0;
    q->block_avail_number = 0;
    q->one_block_len = one_bolck_len - 2;
    q->block_total_num = total_block_num;
    return true;
}

/**
 * @brief :向块状队列中写入一块数据
 * 
 * @param q: 块状队列控制数据结构
 * @param p_array : 需要写入的数据指针
 * @param len : 需要写入的数据长度
 * @param f_irq_dis : 操作过程中是否关闭中断
 * @return true :成功
 * @return false :失败
 */
bool block_queue_write(BlockQueueStruct *q , uint8_t *p_array , uint16_t len , bool f_irq_dis)
{
    uint8_t * pbuf;
    uint32_t psr;

	psr = 0x00;
    if(f_irq_dis)
    {
        psr = csi_irq_save();
    }
    if(len > q->one_block_len)
    {
        if(f_irq_dis)
        {
            csi_irq_restore(psr);
        }
        return false;
    }
    if(q->block_avail_number < q->block_total_num) {  // 队列不满才插入
        //给队伍最尾添加赋值
        pbuf = q->qu[q->tail];
        pbuf[0] = (len & 0xff);
        pbuf[1] = ((len >> 8) & 0xff);
        for(uint16_t i=0;i<len;i++)
        {
            pbuf[i+2] = p_array[i];
        }
        //队尾向后移动一位，如果超过最大值，则从0开始，变成队尾
        q->tail = (q->tail +1)%q->block_total_num;
        //队伍长度+1
        q->block_avail_number ++;
		kb_serial++;
    }else{
        if(f_irq_dis)
        {
            csi_irq_restore(psr);
        }
        return false;
    }
    if(f_irq_dis)
    {
        csi_irq_restore(psr);
    }
    return true;
}

/**
 * @brief :从块状队列中读出一块数据
 * 
 * @param q: 块状队列控制数据结构
 * @param p_array : 需要读出的数据指针
 * @param len : 需要读出的数据长度
 * @param f_irq_dis : 操作过程中是否关闭中断
 * @return true :成功
 * @return false :失败
 */
uint16_t block_queue_read(BlockQueueStruct *q, uint8_t *p_array , uint16_t buf_len , bool f_irq_dis)
{
    uint32_t psr;
    uint8_t * pbuf;
	uint16_t rd_len,i;

    rd_len = 0;
    if(f_irq_dis)
    {        
        psr = csi_irq_save();
    }

    if (q->block_avail_number > 0) {
        pbuf = q->qu[q->head];
        rd_len = pbuf[0] + ((uint16_t)pbuf[1] << 8);
        if(rd_len > buf_len)
        {   // 队列块中数据长度小于要读取的长度
            rd_len = buf_len;
        }
        for(i=0;i<rd_len;i++)
        {
            p_array[i] = pbuf[i+2];
        }
        //队头向后移动一位 超过最大值又重新 从0 开始计算
        q->head = (q->head +1)%q->block_total_num;
        // 队伍长度-1
        q->block_avail_number -- ;
    }else{
        // 队列中数据不够，补充0
        rd_len = 0;
    }

    if(f_irq_dis)
    {
        csi_irq_restore(psr);
    }
	return rd_len;
}

/**
 * @brief :向块状队列的头部写入一块数据,会被优先读取
 *         一般用于应答包，优先填入队列
 * 
 * @param q: 块状队列控制数据结构
 * @param p_array : 需要写入的数据指针
 * @param len : 需要写入的数据长度
 * @param f_irq_dis : 操作过程中是否关闭中断
 * @return true :成功
 * @return false :失败
 */
bool block_queue_write_urgent(BlockQueueStruct *q , uint8_t *p_array , uint16_t len , bool f_irq_dis)
{
    uint8_t * pbuf;
    uint32_t psr;

	psr = 0x00;
    if(f_irq_dis)
    {        
        psr = csi_irq_save();
    }
    if(len > q->one_block_len)
    {
        if(f_irq_dis)
        {
            csi_irq_restore(psr);
        }
        return false;
    }
    if(q->block_avail_number < (q->block_total_num)) {  // 队列不满才插入
        //给队伍最尾添加赋值
        if (q->head == 0)
        {
            q->head = q->block_total_num - 1;
        }else{
            q->head = q->head - 1;
        }        
        pbuf = q->qu[q->head];
        pbuf[0] = (len & 0xff);
        pbuf[1] = ((len >> 8) & 0xff);//(这两个字节是一个uint16_t类型的pbuf)
        for(uint16_t i=0;i<len;i++)
        {
            pbuf[i+2] = p_array[i];//第一个字节表示有多长数据，后续跟队列数据
        }
        //队尾向后移动一位，如果超过最大值，则从0开始，变成队尾
        q->tail = (q->tail +1)%(q->block_total_num);
        //队伍长度+1
        q->block_avail_number ++;
    }else{
        if(f_irq_dis)
        {
            csi_irq_restore(psr);
        }
        return false;
    }
    if(f_irq_dis)
    {
        csi_irq_restore(psr);
    }
	return true;
}

/**
 * @brief :若队列非空，下一个将要读取块的数据长度
 * 
 * @param q: 块状队列控制数据结构
 * @return uint16_t: 将要读取块的长度
 */
uint16_t block_queue_next_block_length(BlockQueueStruct *q)
{
    uint32_t psr;
    uint8_t * pbuf;
    uint16_t rd_len;

    rd_len = 0;
    psr = csi_irq_save();    
    if (q->block_avail_number > 0) {
        pbuf = q->qu[q->head];
        rd_len = pbuf[0] + ((uint16_t)pbuf[1] << 8);
    }
    csi_irq_restore(psr);

    return rd_len;
}

/**
 * @brief :判断队列是否为空
 * 
 * @param q: 块状队列控制数据结构
 * @return true : 队列空
 * @return false :非空
 */
bool block_queue_is_empty(BlockQueueStruct *q)
{    
    uint32_t psr;
    uint16_t  number;

    psr = csi_irq_save();
    number = q->block_avail_number;
    csi_irq_restore(psr);

    if(number == 0)
        return true;
    else 
        return false;
}

/**
 * @brief :判断队列是否为满
 * 
 * @param q: 块状队列控制数据结构
 * @return true : 队列满
 * @return false :未满
 */
bool block_queue_is_full(BlockQueueStruct *q)
{
    uint32_t psr;
    uint16_t  number,total_num;

    psr = csi_irq_save();
    number = q->block_avail_number;
    total_num = q->block_total_num;
    csi_irq_restore(psr);
    if(number == total_num)
        return true;
    else 
        return false;
}

/**
 * @brief :获取块状队列中，当前有多少块数据
 * 
 * @param q: 块状队列控制数据结构
 * @return 块数量
 */
uint16_t block_queue_cur_block_number(BlockQueueStruct *q)
{
    uint32_t psr;
    uint16_t  number;

    psr = csi_irq_save();
    number = q->block_avail_number;
    csi_irq_restore(psr);
    return number;
}


/* [] END OF FILE */
